package com.hmall.search.Service.impl;

import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.hmall.api.client.ItemClient;
import com.hmall.api.dto.ItemDTO;
import com.hmall.common.utils.BeanUtils;
import com.hmall.common.utils.CollUtils;
import com.hmall.search.Service.ISearchService;
import com.hmall.search.domain.po.ItemDoc;
import com.hmall.search.domain.query.ItemPageQuery;
import com.hmall.search.domain.vo.PageVO;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.HttpHost;
import org.apache.lucene.search.TotalHits;
import org.elasticsearch.action.delete.DeleteRequest;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.aggregations.Aggregation;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.Aggregations;
import org.elasticsearch.search.aggregations.bucket.terms.Terms;
import org.elasticsearch.search.aggregations.bucket.terms.TermsAggregationBuilder;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightField;
import org.elasticsearch.search.sort.SortOrder;
import org.elasticsearch.xcontent.XContentType;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.util.*;

@Slf4j
@Service
public class ISearchServiceImpl implements ISearchService {

    private RestHighLevelClient client;
    @Autowired
    private ItemClient itemClient;

    private final static String INDEX_NAME = "items";

    public ISearchServiceImpl() {
        client = new RestHighLevelClient(RestClient.builder(HttpHost.create("http://192.168.56.128:9200")));
    }

    @Override
    public void saveItemById(Long itemId) {

        ItemDTO itemDTO = itemClient.queryItemById(itemId);
        ItemDoc itemDoc = BeanUtils.copyBean(itemDTO, ItemDoc.class);

        IndexRequest request = new IndexRequest(INDEX_NAME).id(itemId.toString());
        request.source(JSONUtil.toJsonStr(itemDoc), XContentType.JSON);

        try {
            client.index(request, RequestOptions.DEFAULT);
        } catch (IOException e) {
            throw new RuntimeException("添加商品异常" + e.getMessage());
        }

    }

    @Override
    public void deleteItemById(Long itemId) {
        DeleteRequest request = new DeleteRequest(INDEX_NAME).id(itemId.toString());
        try {
            client.delete(request, RequestOptions.DEFAULT);
        } catch (IOException e) {
            throw new RuntimeException("删除商品异常" + e.getMessage());
        }

    }

    @Override
    public PageVO<ItemDoc> search(ItemPageQuery query) {
        log.info("搜索商品:{}", query);

        PageVO<ItemDoc> itemDocPageVO = PageVO.empty(0L, 0L);

        SearchRequest request = new SearchRequest(INDEX_NAME);
        BoolQueryBuilder builder = QueryBuilders.boolQuery();

        String 关键字 = query.getKey();
        String 商品分类 = query.getCategory();
        String 商品品牌 = query.getBrand();
        Integer 最高价格 = query.getMaxPrice();
        Integer 最低价格 = query.getMinPrice();
        Integer 页面 = query.getPageNo();
        Integer 页面数量 = query.getPageSize();
        String 排序方式 = query.getSortBy();
        Long 页面总数;
        List<ItemDoc> itemDocs = new ArrayList<>();
        boolean 高亮显示 = false;

        // 查询关键字
        if (StrUtil.isNotBlank(关键字)) {
            log.debug("执行查询关键字成功");
            builder.must(QueryBuilders.matchQuery("name", 关键字));
            高亮显示 = true;
        }

        // 查询商品分类
        if (StrUtil.isNotBlank(商品分类)) {
            log.debug("执行查询商品分类成功");
            builder.filter(QueryBuilders.termsQuery("category", 商品分类));
        }

        // 查询商品品牌
        if (StrUtil.isNotBlank(商品品牌)) {
            log.debug("执行查询商品品牌成功");
            builder.filter(QueryBuilders.termsQuery("brand", 商品品牌));
        }

        // 查询最低价格
        if (最低价格 != null) {
            log.debug("执行查询最低价格成功");
            builder.filter(QueryBuilders.rangeQuery("price").gt(最低价格));
        }

        // 查询最高价格
        if (最高价格 != null) {
            log.debug("执行查询最高价格成功");
            builder.filter(QueryBuilders.rangeQuery("price").lt(最高价格));
        }

        // 排序
        if (StrUtil.isNotBlank(排序方式)) {
            log.debug("执行排序成功");
            request.source().sort(排序方式, query.getIsAsc() ? SortOrder.ASC : SortOrder.DESC);
        }

        // 设置高亮显示
        if (高亮显示) {
            log.debug("高亮设置成功");
            request.source().highlighter(SearchSourceBuilder.highlight().field("name") // 字段名
                    .preTags("<em>") // 开始
                    .postTags("</em>") // 结束
            );
        }

        request.source().from((页面 - 1) * 页面数量).size(页面数量);

        request.source().query(builder);


        log.info("关键字:{},商品分类:{},商品品牌:{},最高价格:{},最低价格:{},页面:{},页面数量:{},排序方式:{},", 关键字, 商品分类, 商品品牌, 最高价格, 最低价格, 页面, 页面数量, 排序方式);


        try {
            SearchResponse response = client.search(request, RequestOptions.DEFAULT);
            log.info("response:{}", response);

            SearchHits hits = response.getHits();

            页面总数 = hits.getTotalHits().value;

            SearchHit[] hitsSource = hits.getHits();
            log.info("HitSource取出的数据: \n {}", hitsSource);
            for (SearchHit hit : hitsSource) {
                String source = hit.getSourceAsString();
                ItemDoc itemDoc = JSONUtil.toBean(source, ItemDoc.class);

                if (高亮显示) {
                    Map<String, HighlightField> map = hit.getHighlightFields();
                    if (map != null && map.containsKey("name")) {
                        HighlightField highlightField = map.get("name");
                        String name = highlightField.fragments()[0].string();
                        itemDoc.setName(name);
                        log.debug("高亮显示成功:{}", itemDoc);
                    }
                }


                itemDocs.add(itemDoc);


            }


        } catch (IOException e) {
            log.info("response:{}", e.getMessage());
            throw new RuntimeException(e);
        }

        long pages = (页面总数 % 页面数量 == 0) ? (页面总数 / 页面数量) : (页面总数 / 页面数量 + 1);
        itemDocPageVO.setTotal(页面总数);
        itemDocPageVO.setList(itemDocs);
        itemDocPageVO.setPages(pages);

        log.info("返回数据:" + getClass() + "为:{}", itemDocPageVO);

        return itemDocPageVO;
    }

    @Override
    public Map<String, List<String>> filters(ItemPageQuery query) {

        return CollUtils.emptyMap();
    }
}
